--
-- Combat rogue rotation helper
--

-- '_G' stuff is to keep lualint happy

if _G['select'](2, _G['UnitClass']('player')) ~= 'ROGUE' then return end

-------------------------------------------
-- Local references to globals for speed and lint's happiness
-------------------------------------------
local _G = _G

local UnitHealth = _G['UnitHealth']
local strsplit = _G['strsplit']
local max = _G['max']
local GetTime = _G['GetTime']
local GetComboPoints = _G['GetComboPoints']
local UnitGUID = _G['UnitGUID']
local UnitCanAttack = _G['UnitCanAttack']
local UnitIsDead = _G['UnitIsDead']

local Rotor = _G['Rotor']

--------------------
local MODULE = 'Rogue'

-------------------------------------------
-- Constants
-------------------------------------------

--
-- Spell ids
--
local SS_ID     = 1752  -- sinister strike
local KS_ID     = 51690 -- killing spree
local AR_ID     = 13750 -- adrenaline rush
local BF_ID     = 13877 -- blade flurry
local SND_ID    = 5171  -- slice'n'dice
local BGG_ID    = 84745 -- bg green phase
local BGY_ID    = 84746 -- bg yellow phase
local BGR_ID    = 84747 -- bg red phase
local RUP_ID    = 1943  -- rupture
local RS_ID     = 84617 -- revealing strike
local EA_ID     = 8647  -- expose armor
local EVIS_ID   = 2098  -- Eviscerate
local TOT_ID    = 57934 -- tricks of the trade
local COS_ID    = 31224 -- cloack of shadows
local VANISH_ID = 1856  -- vanish
local SPRINT_ID = 2983  -- sprint
local RECUP_ID  = 73651 -- recupertate
local FEINT_ID  = 1966
local KICK_ID   = 1766
local STEALTH_ID    = 1784
local BS_ID     = 13877 -- blade storm
local AMBUSH_ID = 8676

-- The module
local Mod = Rotor:NewModule(MODULE)

---------------------------------------------------------
--
-- Spell prediction
--

-- Spell objects
local ks -- killing spree
local ar -- adrenailne rush
local snd -- slice'n'dice
local rs -- revealing strike
local tot -- tricks of the trade

-- Buff objects
local snd_buff -- slice'n'dice
local stealth_buff
local vanish_buff
local tot_buff
local ar_buff

-- Debuff objects
local rup_debuff    -- rupture
local rs_debuff     -- revealing strike

-- Local vars
local now = 0
local gcd = 0

--
-- Methods implementation
--

function Mod:RegisterAuras()
    snd_buff = Rotor:RegisterSelfBuff(SND_ID)
    rup_debuff = Rotor:RegisterDebuff(RUP_ID, true)
    rs_debuff = Rotor:RegisterDebuff(RS_ID, true)
    Rotor:initBlIndicator(4)
    ar_buff = Rotor:RegisterSelfBuff(AR_ID, 1)
    Rotor:RegisterSelfBuff(KS_ID, 1)
    stealth_buff = Rotor:RegisterSelfBuff(STEALTH_ID, 1)
    Rotor:RegisterSelfBuff(BGR_ID, 2)
    Rotor:RegisterSelfBuff(BGY_ID, 2)
    Rotor:RegisterSelfBuff(BGG_ID, 2)
    tot_buff = Rotor:RegisterSelfBuff(TOT_ID, 3)
    Rotor:RegisterSelfBuff(RECUP_ID, 12)
    Rotor:RegisterSelfBuff(BS_ID, 12)
    vanish_buff = Rotor:RegisterSelfBuff(VANISH_ID)
end

function Mod:RegisterSpells()
    Rotor:RegisterSpell(SPRINT_ID, 5)
    Rotor:RegisterSpell(AR_ID, 6)
    Rotor:RegisterSpell(KS_ID, 7)
    tot = Rotor:RegisterSpell(TOT_ID, 8)
    Rotor:RegisterSpell(VANISH_ID, 9)
    Rotor:RegisterSpell(COS_ID, 10)
    Rotor:RegisterSpell(KICK_ID, 11)
    rs = Rotor:RegisterSpell(RS_ID)
    snd = Rotor:RegisterSpell(SND_ID)
end

function Mod:Init(opts)
    self:RegisterAuras()
    self:RegisterSpells()
    Rotor:showPowerDisplay('0')
    Rotor:showUpperText('0')
    return true
end

function Mod:Done()
    ks = nil
    ar = nil
    snd = nil
    rs = nil

    snd_buff = nil

    rup_debuff = nil
    rs_debuff = nil
end


local function CheckUnsent(spell, time_since_last_sent)
    return (spell.sentAt <= spell.doneAt) and (spell.doneAt + (time_since_last_sent or 0.5) < now)
end

local function CheckOffCdAndUnsent(spell, time_since_last_sent, wth)
    return (spell.cd - (wth or 0.4) <= gcd) and CheckUnsent(spell, time_since_last_sent)
end

local function FocusIsToTable()
    return
        UnitGUID('focus')
        and not UnitCanAttack('player', 'focus')
        and not UnitIsDead('focus')
end

function Mod:NextSkill(gcd_arg, cur_spell)
    gcd = max(0.5, gcd_arg)
    now = GetTime()

	local cp = Rotor.combo_points

    if (tot.cd < gcd) and not tot_buff.active and not ar_buff.active and FocusIsToTable() then
        return TOT_ID
    elseif stealth_buff.active or vanish_buff.active then
        return AMBUSH_ID
    elseif (cp > 0 and snd_buff.time_left <= 2) and CheckUnsent(snd, 1.5) then
        return SND_ID
    elseif (cp >= 4) and (snd_buff.time_left <= 4) and CheckUnsent(snd, 1.5) then
        return SND_ID
    elseif (cp == 4 and rs_debuff.time_left == 0) and CheckUnsent(rs, 1.5) then
        return RS_ID
    elseif cp == 5 then
        return EVIS_ID
    else
        return SS_ID
    end
end

-- Command line handler
function Mod:HandleCommandLine(cmd)
    local cmd, args = strsplit(' ', (cmd or ''):lower(), 2)
    -- handle command line here
end

-- Module detection
function Mod:Detect()
    return Rotor.spec == 2 -- combat only for now
end
